package com.ccp.dev.workflow.listener;

import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.system.dao.SysUserDao;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.dao.ActDefModelDao;
import com.ccp.dev.workflow.dao.BpmBusLinkDao;
import com.ccp.dev.workflow.dao.BpmFormRunDao;
import com.ccp.dev.workflow.dao.TaskDao;
import com.ccp.dev.workflow.event.ProcessEndEvent;
import com.ccp.dev.workflow.model.ActDefModel;
import com.ccp.dev.workflow.model.ProcessRun;
import com.ccp.dev.workflow.model.SysTemplate;
import com.ccp.dev.workflow.model.bpm.BpmBusLink;
import com.ccp.dev.workflow.model.bpm.ProcessCmd;
import com.ccp.dev.workflow.service.ProcessCopyToService;
import com.ccp.dev.workflow.service.ProcessRunService;
import com.ccp.dev.workflow.service.SysTemplateService;
import com.ccp.dev.workflow.service.TaskMessageService;
import com.ccp.dev.workflow.service.bpm.thread.TaskThreadService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * ClassDescribe:
 * 结束事件监听器
 * @author :wangcheng
 * Date: 2019-05-13
 */
@Component
public class EndEventListener extends BaseNodeEventListener {
    @Resource
    private ProcessRunService processRunService;
    @Resource
    private ActDefModelDao actDefModelDao;
    @Resource
    private ProcessCopyToService processCopyToService;
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private SysTemplateService sysTemplateService;
    @Resource
    private TaskMessageService taskMessageService;
    @Resource
    private TaskDao taskDao;
    @Resource
    private BpmFormRunDao bpmFormRunDao;
    @Resource
    private BpmBusLinkDao bpmBusLinkDao;

    @Override
    protected void execute(DelegateExecution execution, String procDefId, String nodeId) {
        ExecutionEntity ent=(ExecutionEntity)execution;
        if(!ent.isEnded()){
            return;
        }

        // 当前executionId和主线程相同
        if (ent.getId().equals(ent.getProcessInstanceId()) && ent.getParentId() == null) {
            ProcessRun processRun = processRunService.getByProcInstanceId(ent.getProcessInstanceId());
            handEnd(ent, processRun);
            // 发布流程结束事件
            ProcessEndEvent endEvent = new ProcessEndEvent(processRun);
            endEvent.setExecutionEntity(ent);
            AppUtil.publishEvent(endEvent);
        }
    }

    private void handEnd(ExecutionEntity ent, ProcessRun processRun) {
        // 更新流程实例状态
        updProcessRunStatus(processRun);
        // 删除知会任务
        delNotifyTask(ent);
        // 更新业务中间表
        updBusLink(processRun);
        // 发送抄送
        copyTo(ent, processRun);
    }

    /**
     * 抄送
     * @param ent 执行实例对象
     * @param processRun 流程运行封装对象
     */
    private void copyTo(ExecutionEntity ent, ProcessRun processRun) {
        ProcessCmd processCmd = TaskThreadService.getProcessCmd();
        // 获取流程模型
        ActDefModel actDefModel = actDefModelDao.getById(processRun.getModelId());
        // 获取流程变量
        Map<String, Object> variables = ent.getVariables();
        // 添加抄送任务以及发送提醒
        try {
            processCopyToService.handlerCopyTask(processRun, variables, processCmd.getCurrentUserId(), actDefModel);
            // 处理发送提醒消息给发起人
            if (StringUtil.isNotEmpty(actDefModel.getInformStart())) {
                handSendMsgToStartUser(processRun, actDefModel);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }


    }

    /**
     * 处理发送提醒消息给发起人
     * @param processRun 流程运行封装对象
     * @param actDefModel 流程模型
     */
    private void handSendMsgToStartUser(ProcessRun processRun, ActDefModel actDefModel) throws Exception {
        String informStart = actDefModel.getInformStart();
        if (StringUtil.isEmpty(informStart)) {
            return;
        }
        if (BeanUtils.isEmpty(processRun)) {
            return;
        }
        String subject = processRun.getSubject();
        String startUserId = processRun.getCreatorId();
        SysUser user = sysUserDao.getById(startUserId);
        List<SysUser> receiverUserList = new ArrayList<>();
        receiverUserList.add(user);

        Map<String, String> msgTempMap = sysTemplateService.getTempByFun(SysTemplate.USE_TYPE_NOTIFY_STARTUSER);
        taskMessageService.sendMessage(null,receiverUserList, informStart,msgTempMap, subject, "",null, processRun.getRunId(),null);
    }

    /**
     * 更新业务中间表数据状态
     * @param processRun 流程运行封装对象
     */
    private void updBusLink(ProcessRun processRun) {
        String businessKey = processRun.getBusinessKey();
        BpmBusLink bpmBusLink = new BpmBusLink();
        SysUser currentUser = (SysUser) ContextUtil.getCurrentUser();
        if (BeanUtils.isNotEmpty(currentUser)) {
            bpmBusLink.setBusUpdid(currentUser.getUserId());
            bpmBusLink.setBusUpd(currentUser.getFullName());
        }
        bpmBusLink.setBusStatus(BpmBusLink.BUS_STATUS_END);
        bpmBusLink.setBusUpdtime(new Date());
        bpmBusLink.setBusPkstr(businessKey);
        bpmBusLinkDao.updateStatus(bpmBusLink);
    }

    /**
     * 终止流程时删除流程任务
     *  1.删除流程实例任务
     *  2.删除任务参与者
     *  3.删除流程表单运行情况
     * @param ent 流程实例
     */
    private void delNotifyTask(ExecutionEntity ent) {
        String processInstanceId = ent.getProcessInstanceId();
        // 删除知会任务
        taskDao.delSubCustTaskByInstId(processInstanceId);
        // 删除流程表单运行情况
        bpmFormRunDao.delByInstanceId(processInstanceId);

    }

    /**
     * 更新流程运行状态 为完成
     * @param processRun 流程运行封装对象
     */
    private void updProcessRunStatus(ProcessRun processRun) {
        if (BeanUtils.isEmpty(processRun)) {
            return;
        }
        // 设置流程状态为完成
        processRun.setStatus(ProcessRun.STATUS_FINISH);
        processRunService.update(processRun);

    }

    @Override
    protected Integer getScriptType() {
        return BpmConst.END_SCRIPT;
    }
}
